Skip to content

feat(cli): fbuild port scan with VID:PID friendly-name resolution (#741)#742

Merged
zackees merged 1 commit into
mainfrom
feat/741-port-scan
Jun 21, 2026
Merged

feat(cli): fbuild port scan with VID:PID friendly-name resolution (#741)#742
zackees merged 1 commit into
mainfrom
feat/741-port-scan

Conversation

@zackees

@zackees zackees commented Jun 21, 2026

Copy link
Copy Markdown
Member

Summary

Adds fbuild port scan — enumerates every visible serial port and renders a two-row block per port with vendor + friendly product names resolved from VID:PID.

COM25     303A:1001    USB Serial Device (COM25)    ser=80:F1:B2:D1:DF:B1
          └─ Espressif Systems / ESP32-S3 USB-CDC

COM10     1FC9:0132    USB Serial Device (COM10)    ser=0B03400A
          └─ NXP Semiconductors / LPC-Link2 CMSIS-DAP

4 USB ports, 3 non-USB ports

Row 2 resolves the VID:PID via the tiered fbuild_core::usb resolver:

  • Tier 1: embedded vendor archive (always available)
  • Tier 2: best-effort online overlay fetched from FastLED/fbuild's online-data branch into a 7-day TTL cache under fbuild_paths::get_cache_root().join("usb/")
  • Tier 3: synthetic Device 0xPPPP placeholder

A small inline supplement (FRIENDLY_PRODUCTS) covers common embedded VID:PIDs (ESP32-S3/C3/S2 USB-CDC, NXP LPC-Link2 / MCU-Link) that FastLED/boards' canonical vidpid table doesn't yet carry — those entries should be removed here as they land upstream.

Implementation notes

  • --offline flag skips the network fetch; tier-1 still provides vendor names
  • Atomic cache writes via .tmp sibling + rename — Ctrl+C mid-fetch won't poison the cache
  • reqwest::blocking runs on a dedicated OS thread so its internal tokio runtime doesn't panic from nesting inside the CLI dispatcher's #[tokio::main] outer runtime
  • Pure render_scan() function tested in isolation (11 unit tests pinning layout, summary pluralization, descriptor preference, supplement hits, non-USB ports)

Test plan

  • cargo test -p fbuild-cli --bin fbuild cli::port_scan — 11/11 pass
  • Live fbuild port scan on a system with 4 ESP32-S3 + 1 NXP device — friendly names render correctly
  • cargo clippy -p fbuild-cli --all-targets -- -D warnings — clean
  • cargo fmt — applied

Closes #741

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added fbuild port scan command to enumerate serial ports with USB vendor/product resolution
    • --offline flag available to skip online overlay updates
    • Automatic local caching of USB vendor data with 7-day refresh

Adds `fbuild port scan` — enumerates every visible serial port and
renders a two-row block per port:

  COM25     303A:1001    USB Serial Device (COM25)    ser=80:F1:B2:...
            └─ Espressif Systems / ESP32-S3 USB-CDC

Row 2 resolves the VID:PID via the tiered fbuild_core::usb resolver
(tier 1 embedded vendor archive, tier 2 best-effort online overlay
fetched from FastLED/fbuild's online-data branch into a 7-day TTL
cache under fbuild_paths::get_cache_root().join("usb/")).

Beyond the resolver, the product column falls through this preference
chain so common embedded VID:PIDs the canonical FastLED/boards vidpid
table doesn't yet carry still render a friendly name:

  1. Resolver product if non-synthetic (overlay hit)
  2. Small inline supplement (ESP32 series, NXP LPC-Link2 / MCU-Link)
  3. OS descriptor when chip-specific (e.g. macOS / Linux CP2102 strings)
  4. Synthetic `Device 0xPPPP` placeholder

The blocking HTTP fetch runs on a dedicated OS thread so reqwest's
internal tokio runtime sees a clean async-free context — calling it
directly from inside the CLI dispatcher's #[tokio::main] outer runtime
would panic.

Closes #741
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a15a87a5-d267-4f35-b08a-dee490c0f69d

📥 Commits

Reviewing files that changed from the base of the PR and between b54461b and b4e20f2.

📒 Files selected for processing (4)
  • crates/fbuild-cli/src/cli/args.rs
  • crates/fbuild-cli/src/cli/dispatch.rs
  • crates/fbuild-cli/src/cli/mod.rs
  • crates/fbuild-cli/src/cli/port_scan.rs

📝 Walkthrough

Walkthrough

A new fbuild port scan subcommand is added to the CLI. It enumerates all visible serial ports, optionally refreshes a cached USB VID overlay (7-day TTL, fetched from USB_VID_JSON_URL on a dedicated thread), then renders two rows per port showing the port path/VID:PID and the resolved vendor/product name, plus a summary count line.

Changes

fbuild port scan subcommand

Layer / File(s) Summary
CLI registration and entry point
crates/fbuild-cli/src/cli/mod.rs, crates/fbuild-cli/src/cli/args.rs, crates/fbuild-cli/src/cli/dispatch.rs, crates/fbuild-cli/src/cli/port_scan.rs
Declares the port_scan module, adds Commands::Port { action: PortAction } to the top-level enum, wires run_port into the dispatcher's match arm, and defines PortAction::Scan { offline } with the run_port entry point.
Scan execution and online overlay cache fetch
crates/fbuild-cli/src/cli/port_scan.rs
Implements scan execution: computes the overlay cache path, checks a 7-day TTL, fetches the JSON overlay via reqwest::blocking on a dedicated OS thread, writes it atomically via .tmp+rename, installs it into fbuild_core::usb, then calls serialport::available_ports and prints the rendered output.
render_scan formatter, product label helpers, and unit tests
crates/fbuild-cli/src/cli/port_scan.rs
Adds the pure render_scan formatter (two rows + blank separators per port, plural-correct summary), USB row rendering via fbuild_core::usb::resolve, friendly_product_name label selection (resolver → supplement table → OS descriptor → synthetic fallback), is_generic_descriptor classifier, the FRIENDLY_PRODUCTS table, render_non_usb, and unit tests covering all formatting behaviors.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant fbuild_cli as fbuild CLI dispatcher
  participant run_scan as run_scan()
  participant CacheFS as Cache FS
  participant USB_VID_JSON_URL
  participant fbuild_core_usb as fbuild_core::usb
  participant serialport

  User->>fbuild_cli: fbuild port scan [--offline]
  fbuild_cli->>run_scan: run_port(PortAction::Scan { offline })
  alt not --offline
    run_scan->>CacheFS: check overlay cache age (7-day TTL)
    alt cache stale or missing
      run_scan->>USB_VID_JSON_URL: GET overlay JSON (dedicated OS thread, 15s timeout)
      USB_VID_JSON_URL-->>run_scan: JSON bytes
      run_scan->>CacheFS: write .tmp → rename to cache file
    end
    run_scan->>fbuild_core_usb: install_overlay(bytes)
  end
  run_scan->>serialport: available_ports()
  serialport-->>run_scan: Vec<SerialPortInfo>
  loop per port
    run_scan->>fbuild_core_usb: resolve(vid, pid)
    fbuild_core_usb-->>run_scan: UsbInfo { vendor, product }
  end
  run_scan-->>User: rendered two-row-per-port output + summary
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A bunny hops up to the serial port,
sniffing each VID with a curious snort.
└─ Espressif / ESP32-S3 it cries!
Two tidy rows gleam before my eyes.
From cached overlays to synthetic fall-through,
every device gets a label brand new! 🐇✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/741-port-scan

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@zackees zackees merged commit a5baf02 into main Jun 21, 2026
84 of 91 checks passed
@zackees zackees deleted the feat/741-port-scan branch June 21, 2026 08:38
@fastled-project-sync fastled-project-sync Bot moved this to Triage in FastLED Tracker Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

feat(cli): fbuild port scan — enumerate ports + resolve VID:PID to vendor/product via FastLED/boards

1 participant